import doAlign from './align';
import getOffsetParent from '../getOffsetParent';
import getVisibleRectForElement from '../getVisibleRectForElement';
import getRegion from '../getRegion';

/**
 * 判断目标元素是否完全位于可见矩形区域之外,即判断元素是否完全不可见（超出视口或祖先元素的可见区域）。
 * @param  target: 需要检测的目标元素
 * @param  alwaysByViewport: 是否始终基于视口检测（忽略祖先元素的溢出限制）
 * @return {Boolean}
 */
function isOutOfVisibleRect(target, alwaysByViewport) {
  // 获取目标元素的可见矩形区域（visibleRect）
  const visibleRect = getVisibleRectForElement(target, alwaysByViewport);
  // 获取目标元素相对于文档的区域（targetRegion），包括 left、top、width、height 等属性。
  const targetRegion = getRegion(target);

  // 判断目标元素是否在可见矩形之外,条件如下：
  // a. 如果 visibleRect 不存在（即元素不在任何文档中或不可见），则返回 true（表示在可见区域外）。
  // b. 目标元素的右边界（left + width）小于等于可见矩形的左边界（visibleRect.left） -> 表示目标元素在可见矩形的左侧之外。
  // c. 目标元素的下边界（top + height）小于等于可见矩形的上边界（visibleRect.top） -> 表示目标元素在可见矩形的上方之外。
  // d. 目标元素的左边界（left）大于等于可见矩形的右边界（visibleRect.right） -> 表示目标元素在可见矩形的右侧之外。
  // e. 目标元素的上边界（top）大于等于可见矩形的下边界（visibleRect.bottom） -> 表示目标元素在可见矩形的下方之外。

  // 返回值：如果满足上述任意一个条件，则返回 true（表示目标元素完全在可见矩形之外），否则返回 false。
  return (
    !visibleRect ||
    targetRegion.left + targetRegion.width <= visibleRect.left ||
    targetRegion.top + targetRegion.height <= visibleRect.top ||
    targetRegion.left >= visibleRect.right ||
    targetRegion.top >= visibleRect.bottom
  );
}

/**
 * 将el元素根据参考节点refNode按照align配置进行对齐。
 * 
 * @param  el: 需要定位的源元素
 * @param  refNode: 对齐的参考元素
 * @param  align: 对齐配置对象
 * @return {[type]}
 */
function alignElement(el, refNode, align) {
  // 1. 确定目标元素（target）：如果align中指定了target，则使用align.target，否则使用refNode。
  const target = align.target || refNode;
  // 2. 获取目标元素的区域信息（refNodeRegion）。
  const refNodeRegion = getRegion(target);

  // 3. 判断目标元素是否在可见区域内（isTargetNotOutOfVisible）。
  const isTargetNotOutOfVisible = !isOutOfVisibleRect(
    target,
    align.overflow && align.overflow.alwaysByViewport,
  );

  return doAlign(el, refNodeRegion, align, isTargetNotOutOfVisible);
}

alignElement.__getOffsetParent = getOffsetParent;

alignElement.__getVisibleRectForElement = getVisibleRectForElement;

export default alignElement;
